package com.ayh.campusfun.controller.api.v1.websocket;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.ayh.campusfun.common.utils.PraMap;
import com.ayh.campusfun.controller.api.v1.param.MessageParam;
import com.ayh.campusfun.entity.Users;
import com.ayh.campusfun.service.MessageService;
import com.ayh.campusfun.service.UsersService;
import com.ayh.campusfun.vo.CommonMessageVO;
import com.ayh.campusfun.vo.StudyVO;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;


/**
 * @author ayh
 * @create 2021/4/10 0010 22:14
 * 添加好友消息推送
 */


@ServerEndpoint("/studyRoom/{uid}/{roomType}")
@Component
@Slf4j
@Data
public class StudyRoomSocket {

    private static MessageService messageService;

    @Autowired
    public void setMessageService(MessageService messageService) {
        StudyRoomSocket.messageService = messageService;
    }

    private static UsersService usersService;

    @Autowired
    public void setUsersService(UsersService usersService) {
        StudyRoomSocket.usersService = usersService;
    }

    public static final Map<String, StudyRoomSocket> studyRoom1 = new LinkedHashMap<>();
    public static final Map<String, StudyRoomSocket> studyRoom2 = new LinkedHashMap<>();
    public static final Map<String, StudyRoomSocket> studyRoom3 = new LinkedHashMap<>();
    public static final Map<String, StudyRoomSocket> studyRoom4 = new LinkedHashMap<>();

    public static final List<StudyVO> studyVOList1 = new ArrayList<>();
    public static final List<StudyVO> studyVOList2 = new ArrayList<>();
    public static final List<StudyVO> studyVOList3 = new ArrayList<>();
    public static final List<StudyVO> studyVOList4 = new ArrayList<>();

    //记录当前在线数目
    private static int count = 0;

    //当前连接（每个websocket连入都会创建一个AddFriendSocket实例
    private Session session;

    //在线用户的信息
    private StudyVO studyVO;

    //处理连接建立
    @OnOpen
    public void onOpen(Session session, @PathParam("uid") String uid, @PathParam("roomType") Integer roomType) {
        try {
            this.session = session;
            Users users = usersService.findByParam(PraMap.create().put("uid", uid));
            studyVO = new StudyVO();
            BeanUtil.copyProperties(users, studyVO);
            studyVO.setOnlineTime(0L);
            switch (roomType) {
                case 1:
                    studyRoom1.put(uid, this);
                    studyVOList1.removeIf(v -> v.getUid().equals(uid));
                    studyVOList1.add(studyVO);
                    break;
                case 2:
                    studyRoom2.put(uid, this);
                    studyVOList2.removeIf(v -> v.getUid().equals(uid));
                    studyVOList2.add(studyVO);
                    break;
                case 3:
                    studyRoom3.put(uid, this);
                    studyVOList3.removeIf(v -> v.getUid().equals(uid));
                    studyVOList3.add(studyVO);
                    break;
                case 4:
                    studyRoom4.put(uid, this);
                    studyVOList4.removeIf(v -> v.getUid().equals(uid));
                    studyVOList4.add(studyVO);
                    break;
                default:
                    break;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        addCount();
        StudyRoomSocket.broadcast(roomType);
        log.error("新的连接加入：{}", session.getId());
    }

    //接受消息
    @OnMessage
    public void onMessage(String message, Session session) {
        log.error("收到客户端{}消息：{}", session.getId(), message);
        try {
            MessageParam msg = JSON.parseObject(message, new TypeReference<MessageParam>() {
            });
            switch (msg.getRoomType()) {
                case 1: {
                    if (msg.getMessageType() == 1) {
                        studyRoom1.get(msg.getUid()).updateOnlineTime(msg.getOnLineTime());
                    } else if (msg.getMessageType() == 2) {
                        studyRoom1.remove(msg.getUid());
                        studyVOList1.removeIf(v -> v.getUid().equals(msg.getUid()));
                    }
                }
                break;
                case 2: {
                    if (msg.getMessageType() == 1) {
                        studyRoom2.get(msg.getUid()).updateOnlineTime(msg.getOnLineTime());
                    } else if (msg.getMessageType() == 2) {
                        studyRoom2.remove(msg.getUid());
                        studyVOList2.removeIf(v -> v.getUid().equals(msg.getUid()));
                    }
                }
                break;
                case 3: {
                    if (msg.getMessageType() == 1) {
                        studyRoom3.get(msg.getUid()).updateOnlineTime(msg.getOnLineTime());
                    } else if (msg.getMessageType() == 2) {
                        studyRoom3.remove(msg.getUid());
                        studyVOList3.removeIf(v -> v.getUid().equals(msg.getUid()));
                    }
                }
                break;
                case 4: {
                    if (msg.getMessageType() == 1) {
                        studyRoom4.get(msg.getUid()).updateOnlineTime(msg.getOnLineTime());
                    } else if (msg.getMessageType() == 2) {
                        studyRoom4.remove(msg.getUid());
                        studyVOList4.removeIf(v -> v.getUid().equals(msg.getUid()));
                    }
                }
                break;
                default:
                    break;
            }
            broadcast(msg.getRoomType());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //处理错误
    @OnError
    public void onError(Throwable error, Session session) {
        log.info("发生错误{},{}", session.getId(), error.getMessage());
    }

    //处理连接关闭
    @OnClose
    public void onClose() {
        reduceCount();
        log.info("连接关闭:{}", this.session.getId());
    }

    //群发消息

    //发送消息
    public void sendMessage(String message) throws IOException {
        //webSocketMap.get("12345676").session.getBasicRemote().sendText(message);
        this.session.getBasicRemote().sendText(message);
    }

    public void updateOnlineTime(Long onlineTime) throws IOException {
        this.studyVO.setOnlineTime(onlineTime);
    }

    //广播消息
    public static void broadcast(Integer roomType) {
        switch (roomType) {
            case 1:
                studyRoom1.forEach((k, v) -> {
                    try {
                        v.sendMessage(JSON.toJSONString(CommonMessageVO.build(2, count, studyVOList1)));
                    } catch (Exception e) {
                    }
                });
                break;
            case 2:
                studyRoom2.forEach((k, v) -> {
                    try {
                        v.sendMessage(JSON.toJSONString(CommonMessageVO.build(2, count, studyVOList2)));
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                });
                break;
            case 3:
                studyRoom3.forEach((k, v) -> {
                    try {
                        v.sendMessage(JSON.toJSONString(CommonMessageVO.build(2, count, studyVOList3)));
                    } catch (Exception e) {
                    }
                });
                break;
            case 4:
                studyRoom4.forEach((k, v) -> {
                    try {
                        v.sendMessage(JSON.toJSONString(CommonMessageVO.build(2, count, studyVOList4)));
                    } catch (Exception e) {
                    }
                });
                break;
        }
    }

    //获取在线连接数目
    public static int getCount() {
        return count;
    }

    //操作count，使用synchronized确保线程安全
    public static synchronized void addCount() {
        StudyRoomSocket.count++;
    }

    public static synchronized void reduceCount() {
        StudyRoomSocket.count--;
    }

}